<template>
	<view class="u-wrap" :style="{
			  opacity: Number(opacity),
			  borderRadius: borderRadius + 'rpx',
			  // 因为time值需要改变,所以不直接用duration值(不能改变父组件prop传过来的值)
			  transition: `opacity ${time / 1000}s ease-in-out`
		   }"
	 :class="'u-lazy-item-' + elIndex">
		<view :class="'u-lazy-item-' + elIndex">
			<image :style="{borderRadius: borderRadius + 'rpx', height: imgHeight}" v-if="!isError" class="u-lazy-item"
			 :src="isShow ? image : loadingImg" :mode="imgMode" @load="imgLoaded" @error="loadError" @tap="clickImg"></image>
			<image :style="{borderRadius: borderRadius + 'rpx', height: imgHeight}" class="u-lazy-item error" v-else :src="errorImg"
			 :mode="imgMode" @load="errorImgLoaded" @tap="clickImg"></image>
		</view>
	</view>
</template>

<script>
	
	export default {
		name: 'u-lazy-load',
		props: {
			index: {
				type: [Number, String]
			},
			
			image: {
				type: String,
				default: ''
			},
			
			imgMode: {
				type: String,
				default: 'widthFix'
			},
			
			loadingImg: {
				type: String,
				default: ''
			},
			
			errorImg: {
				type: String,
				default: ''
			},
			
			
			threshold: {
				type: [Number, String],
				default: 100
			},
			
			duration: {
				type: [Number, String],
				default: 500
			},
			
			
			effect: {
				type: String,
				default: 'ease-in-out'
			},
			
			isEffect: {
				type: Boolean,
				default: true
			},
			
			borderRadius: {
				type: [Number, String],
				default: 0
			},
			
			height: {
				type: [Number, String],
				default: '450'
			}
		},
		data() {
			return {
				isShow: false,
				opacity: 1,
				time: this.duration,
				loadStatus: '', 
				isError: false, 
				elIndex: this.$u.guid()
			}
		},
		computed: {
			
			getThreshold() {
				
				let thresholdPx = uni.upx2px(Math.abs(this.threshold));
				return this.threshold < 0 ? -thresholdPx : thresholdPx;
			},
			
			imgHeight() {
				return this.$u.addUnit(this.height);
			}
		},
		created() {
			
			this.observer = {};
		},
		watch: {
			isShow(nVal) {
				
				if (!this.isEffect) return;
				this.time = 0;
				
				this.opacity = 0;
				
				setTimeout(() => {
					this.time = this.duration;
					this.opacity = 1;
				}, 30)
			},
			
			image(n) {
				if(!n) {
					
					this.isError = true;
				} else {
					this.init();
					this.isError = false;
				}
			}
		},
		methods: {
			
			init() {
				this.isError = false;
				this.loadStatus = '';
			},
			
			clickImg() {
				let whichImg = '';
				
				if (this.isShow == false) whichImg = 'lazyImg';
				
				
				else if (this.isError == true) whichImg = 'errorImg';
				
				else whichImg = 'realImg';
				
				this.$emit('click', this.index);
			},
			
			imgLoaded() {
				
				if (this.loadStatus == '') {
					this.loadStatus = 'lazyed';
				}
				
				else if (this.loadStatus == 'lazyed') {
					this.loadStatus = 'loaded';
					this.$emit('load', this.index);
				}
			},
			
			errorImgLoaded() {
				this.$emit('error', this.index);
			},
			
			loadError() {
				this.isError = true;
			},
			disconnectObserver(observerName) {
				const observer = this[observerName];
				observer && observer.disconnect();
			},
		},
		beforeDestroy() {
			
			
		},
		mounted() {
			
			this.$nextTick(() => {
				uni.$once('uOnReachBottom', () => {
					if (!this.isShow) this.isShow = true;
				});
			})
			
			setTimeout(() => {
				
				this.disconnectObserver('contentObserver');
				const contentObserver = uni.createIntersectionObserver(this);
				
				
				contentObserver.relativeToViewport({
					bottom: this.getThreshold,
				}).observe('.u-lazy-item-' + this.elIndex, (res) => {
					if (res.intersectionRatio > 0) {
						
						this.isShow = true;
						
						this.disconnectObserver('contentObserver');
					}
				})
				this.contentObserver = contentObserver;
			}, 30)
		}
	}
</script>

<style scoped lang="scss">
	@import "../../libs/css/style.components.scss";
	
	.u-wrap {
		background-color: #eee;
		overflow: hidden;
	}

	.u-lazy-item {
		width: 100%;
		
		transform: transition3d(0, 0, 0);
		
		will-change: transform;
		/* #ifndef APP-NVUE */
		display: block;
		/* #endif */
	}
</style>
